API: Add gtk_cairo_should_draw_window()
authorBenjamin Otte <otte@redhat.com>
Thu, 2 Sep 2010 21:26:13 +0000 (23:26 +0200)
committerBenjamin Otte <otte@redhat.com>
Sun, 26 Sep 2010 13:11:35 +0000 (15:11 +0200)
See the function documentation for its purpose and the next commit(s)
for examples on how to use it.

gtk/gtk.symbols
gtk/gtkwidget.c

index 867f490abd15e7351bfe8a8d808e1d119aeece06..30923d365831a5f3ce002a872bf39c374aedfed6 100644 (file)
@@ -4176,6 +4176,7 @@ gtk_vseparator_new
 
 #if IN_HEADER(__GTK_WIDGET_H__)
 #if IN_FILE(__GTK_WIDGET_C__)
+gtk_cairo_should_draw_window
 gtk_requisition_copy
 gtk_requisition_free
 gtk_requisition_get_type G_GNUC_CONST
index 9ea11ad282309441540ed4f19f7d912c5fa62ff0..fb63f4b51ac408d5bc476128b83be7debd0fa728 100644 (file)
@@ -5070,10 +5070,59 @@ gtk_widget_real_mnemonic_activate (GtkWidget *widget,
   return TRUE;
 }
 
+static const cairo_user_data_key_t window_key;
+
+static GdkWindow *
+gtk_cairo_get_window (cairo_t *cr)
+{
+  g_return_val_if_fail (cr != NULL, NULL);
+
+  return cairo_get_user_data (cr, &window_key);
+}
+
+/**
+ * gtk_cairo_should_draw_window:
+ * @cr: a cairo context
+ * @window: the window to check
+ *
+ * This function is supposed to be called in GtkWidget::draw
+ * implementations for widgets that support multiple windows.
+ * @cr must be untransformed from invoking of the draw function.
+ * This function will return %TRUE if the contents of the given
+ * @window are supposed to be drawn and %FALSE otherwise. Note
+ * that when the drawing was not initiated by the windowing
+ * system this function will return %TRUE for all windows, so
+ * you need to draw the bottommost window first. Also, do not
+ * use "else if" statements to check which window should be drawn.
+ *
+ * Returns: %TRUE if @window should be drawn
+ **/
+gboolean
+gtk_cairo_should_draw_window (cairo_t *cr,
+                              GdkWindow *window)
+{
+  GdkWindow *cairo_window;
+
+  g_return_val_if_fail (cr != NULL, FALSE);
+  g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
+
+  cairo_window = gtk_cairo_get_window (cr);
+  
+  return cairo_window == NULL ||
+         cairo_window == window;
+}
+
+static void
+gtk_cairo_set_window (cairo_t   *cr,
+                      GdkWindow *window)
+{
+  cairo_set_user_data (cr, &window_key, window, NULL);
+}
 static gboolean
 gtk_widget_real_expose_event (GtkWidget      *widget,
                              GdkEventExpose *expose)
 {
+  GdkWindow *window;
   gboolean result = FALSE;
   cairo_t *cr;
 
@@ -5081,9 +5130,34 @@ gtk_widget_real_expose_event (GtkWidget      *widget,
     return FALSE;
 
   cr = gdk_cairo_create (expose->window);
+  gtk_cairo_set_window (cr, expose->window);
+
   gdk_cairo_region (cr, expose->region);
   cairo_clip (cr);
 
+  /* translate cairo context properly */
+  window = gtk_widget_get_window (widget);
+  if (window != expose->window)
+    {
+      int x, y;
+
+      if (gdk_window_get_parent (expose->window) == window)
+        {
+          gdk_window_get_position (expose->window, &x, &y);
+        }
+      else
+        {
+          int ex, ey;
+          gdk_window_get_origin (expose->window, &ex, &ey);
+          gdk_window_get_origin (window, &x, &y);
+          x = ex - x;
+          y = ey - y;
+        }
+
+      cairo_translate (cr, -x, -y);
+    }
+
+
   if (!gtk_widget_get_has_window (widget))
     {
       cairo_translate (cr,
@@ -5094,7 +5168,10 @@ gtk_widget_real_expose_event (GtkWidget      *widget,
   g_signal_emit (widget, widget_signals[DRAW], 
                  0, cr,
                  &result);
-                
+
+  /* unset here, so if someone keeps a reference to cr we
+   * don't leak the window. */
+  gtk_cairo_set_window (cr, NULL);
   cairo_destroy (cr);
 
   return result;